package cn.justforchris.blog.service.impl;


import cn.justforchris.blog.domain.ArticleType;
import cn.justforchris.blog.dto.ArticleDto;
import cn.justforchris.blog.mapper.ArticleTypeMapper;
import cn.justforchris.blog.query.QueryPage;
import cn.justforchris.blog.service.IArticleTypeService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 文章类型服务实现类
 */
@Service
@Slf4j
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
@CacheConfig(cacheNames = "ArticleType")
public class ArticleTypeServiceImpl implements IArticleTypeService {

    @Autowired
    private ArticleTypeMapper articleTypeMapper;

//    @Autowired
//    private RedisTemplate redisTemplate;


    /**
     * 插入文章类型
     * @param articleType
     */
    @Override
    @Transactional
    @CacheEvict(key = "'typeTree'") /*在对数据有操作的方法上需要加上此注解以删除缓存,用于删除旧数据,将新数据写入缓存*/
    public void insertArticleType(ArticleType articleType) {

        Date date = new Date();
        articleType.setCreateTime(date);
        articleTypeMapper.insertArticleType(articleType);
    }

    /**
     * 删除文章类型
     * @param id
     */
    @Override
    @Transactional
    @CacheEvict(key = "'typeTree'") /*在对数据有操作的方法上需要加上此注解以删除缓存,用于删除旧数据,将新数据写入缓存*/
    public void deleteArticleType(Long id) {

        articleTypeMapper.deleteArticleType(id);
    }

    /**
     * 批量删除文章类型
     * @param ids
     */
    @Override
    @Transactional
    @CacheEvict(key = "'typeTree'") /*在对数据有操作的方法上需要加上此注解以删除缓存,用于删除旧数据,将新数据写入缓存*/
    public void patchDelete(Long[] ids) {

        articleTypeMapper.patchDelete(ids);
    }


    /**
     * 更新文章类型
     * @param articleType
     */
    @Override
    @Transactional
    @CacheEvict(key = "'typeTree'") /*在对数据有操作的方法上需要加上此注解以删除缓存,用于删除旧数据,将新数据写入缓存*/
    public void updateArticleType(ArticleType articleType) {

        articleTypeMapper.updateArticleType(articleType);
    }

    /**
     * 根据id获取文章类型
     * @param id
     * @return
     */
    @Override
    public ArticleType getArticleTypeById(Long id) {
        return articleTypeMapper.getArticleTypeById(id);
    }

    /**
     * 获取所有文章类型
     * @return
     */
    @Override
    public List<ArticleType> getAll() {
        return articleTypeMapper.getAll();
    }

    /**
     * 分页查询文章类型
     * @param queryPage
     * @return
     */
    @Override
    public PageInfo<ArticleType> queryPage(QueryPage queryPage) {
        PageHelper.startPage(queryPage.getCurrentPage(),queryPage.getPageSize());
        List<ArticleType> data = articleTypeMapper.queryPage(queryPage);
        /*
        这里获取到的是符合传入参数currentpage和pagesize的数据,也就是说,如果不传pagesize就只有五条因为怕个size如果不传入的话就是5
        但是如果有pagesize传入就根据传入数据来
        */
        return new PageInfo<>(data);
        /*这里面就包含了pagehelper帮忙计算出来的total(总共多少条,和根据分页提取出的数据)*/

    }

    /**
     * 使用springcache注解(@Cacheable(key = "'typeTree'")),在redis中查询是否存在数据,如果没有就调用方法获取数据,并将其存入redis中,然后返回
     * @return
     */
    @Override
    @Cacheable(key = "'typeTree'")
    public List<ArticleType> getTypeTree() {
//        Object o = redisTemplate.opsForValue().get("TypeTree");
//        /*先判断redis中是否有数据*/
//        if(o==null){
//            /*如果没有数据就调用方法获取数据*/
//            List<ArticleType> typeTree = TypeTree();
//            /*并将其存入redis中*/
//            redisTemplate.opsForValue().set("TypeTree",typeTree);
//            /*返回取到的集合*/
//            return typeTree;
//        }
            return typeTree();
        /*如果有,则返回redis中的集合,这里做了一个强转,因为Redis中的数据获取出来是一个对象,但是我们
        明确知道这是一个集合所以可以强转
        */
    }



    /**
     * 用于获取typeTree的方法
     * @return
     */
    private List<ArticleType> typeTree() {
        /*第一步,获取所有的数据对象*/
        List<ArticleType> types = articleTypeMapper.getAll();
        /*为了提高效率并且,容易获取到父类型对象,所以创建一个map集合用来存放id和对象*/
        Map<Long,ArticleType> map = new HashMap<>();
        /*循环获取到的数据对象,将对象放入map集合中*/
        for (ArticleType type : types) {
            map.put(type.getId(),type);
        }
        /*第三步,创建一个集合用于存放父类型数据对象*/
        List<ArticleType> typeTree = new ArrayList<>();
        /*遍历集合types判断是否有父类型,如果没有就将当前对象放入集合中*/
        for (ArticleType type : types) {
            if (type.getParentId()==null){
                typeTree.add(type);
            }else {
                /*如果有父类型,就通过父类型id获取到父类型对象,然后将当前对象放入父类型对象的children集合中*/
                /*不过,为了避免空指针异常,需要判断父类型是否存在*/
                ArticleType parentType = map.get(type.getParentId());
                if (parentType!=null) {
                    List<ArticleType> children = parentType.getChildren();
                    children.add(type);
                }
            }
            }
        return typeTree;
        }


}



